﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DBSchemaViewer.BackEnd.Entities;
using DBSchemaViewer.FrontEnd.DiagramUserControls.Interfaces;
using DBSchemaViewer.FrontEnd.DiagramUserControls.CustomEvents;

namespace DBSchemaViewer.FrontEnd.DiagramUserControls
{
    public partial class CtlDBRelationship : UserControl, ISelectable
    {
       Point _origin;
        Point _destination;

        double _offsetXOriginMainLine = 5;

        double _sizeYForkVertical = 10;
        //double _offsetXForkVertical = 5;
        double _offsetXForkHorizontal = 5;

        public EntityRelation EntityRelation_info { get; set; }

        /// <summary>
        /// This flag will tell us if the object has been selected
        /// </summary>
        bool _isObjectSelected = false;


        public Point Origin { 
            get
            {
                return _origin;
            }

            set
            {
                _origin = value;
              
                // Setup the initial small origin line
                lnOriginEndPoint.X1 = _origin.X;
                lnOriginEndPoint.Y1 = _origin.Y;
                lnOriginEndPoint.X2 = _origin.X + _offsetXOriginMainLine;
                lnOriginEndPoint.Y2 = _origin.Y;


                // Setup the main line origin
                lnMainLine.X1 = _origin.X + _offsetXOriginMainLine;
                lnMainLine.Y1 = _origin.Y;

            }
        }


        public Point Destination
        {
            get
            {
                return _destination;
            }

            /*set
            {
                _destination = value;

                // Setup the vertical line fork
                lnForkVertical.X1 = _destination.X - _offsetXForkHorizontal;
                lnForkVertical.Y1 = _destination.Y - (_sizeYForkVertical / 2);
                lnForkVertical.X2 = _destination.X - _offsetXForkHorizontal;
                lnForkVertical.Y2 = _destination.Y + (_sizeYForkVertical / 2);
                
                // Setup the upper horizontal line fork
                lnForkUpper.X1 = _destination.X - _offsetXForkHorizontal;
                lnForkUpper.Y1 = _destination.Y - (_sizeYForkVertical /2);
                lnForkUpper.X2 = _destination.X;
                lnForkUpper.Y2 = _destination.Y - (_sizeYForkVertical /2);

                // Setup the middle horizontal line fork
                lnForkMiddle.X1 = _destination.X - _offsetXForkHorizontal;
                lnForkMiddle.Y1 = _destination.Y;
                lnForkMiddle.X2 = _destination.X;
                lnForkMiddle.Y2 = _destination.Y;

                // Setup the lower line
                lnForkLower.X1 = _destination.X - _offsetXForkHorizontal;
                lnForkLower.Y1 = _destination.Y + (_sizeYForkVertical / 2); 
                lnForkLower.X2 = _destination.X;
                lnForkLower.Y2 = _destination.Y + (_sizeYForkVertical / 2);

                // Setup the main line                
                lnMainLine.X2 = _destination.X - _offsetXForkHorizontal;
                lnMainLine.Y2 = _destination.Y;
                
            }*/
        }

        /// <summary>
        /// Delegate and event, LeftButtonDown on the connector (just the lines) / field, propagate to the parent
        /// canvas
        /// </summary>
        /// <param name="o"></param>
        /// <param name="e"></param>
        public delegate void LButtonDownBubblingEventHandler(object o, RelationCtlMouseOperationBubblingArgs e);
        public event LButtonDownBubblingEventHandler LButtonDownBubbled;


        public CtlDBRelationship()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Need to know the destination in order to show the begin line connector twisted or not
        /// this one has not an special "in between" case like the end connector (fork)
        /// </summary>
        /// <param name="ptOrigin"></param>
        /// <param name="ptDestination"></param>
        protected void SetOrigin(Point ptOrigin, Point ptDestination, bool doNotShowTwistedBeginConnector)
        {
            int iXBeginConnectorDirection = (doNotShowTwistedBeginConnector || ptOrigin.X < ptDestination.X) ? 1 : -1;

            _origin = ptOrigin;

            // Setup the initial small origin line
            lnOriginEndPoint.X1 = _origin.X;
            lnOriginEndPoint.Y1 = _origin.Y;
            lnOriginEndPoint.X2 = _origin.X + (_offsetXOriginMainLine * iXBeginConnectorDirection);
            lnOriginEndPoint.Y2 = _origin.Y;


            // Setup the main line origin
            lnMainLine.X1 = _origin.X + (_offsetXOriginMainLine * iXBeginConnectorDirection);
            lnMainLine.Y1 = _origin.Y;

        }

        protected void SetDestination(Point ptDestination, bool showTwistedFork)
        {
            int iXForkDirection = (showTwistedFork == false && _origin.X < ptDestination.X) ? 1 : -1;

            _destination = ptDestination;

            // Setup the vertical line fork
            lnForkVertical.X1 = _destination.X - (_offsetXForkHorizontal * iXForkDirection);
            lnForkVertical.Y1 = _destination.Y - (_sizeYForkVertical / 2);
            lnForkVertical.X2 = _destination.X - (_offsetXForkHorizontal * iXForkDirection);
            lnForkVertical.Y2 = _destination.Y + (_sizeYForkVertical / 2);

            // Setup the upper horizontal line fork
            lnForkUpper.X1 = _destination.X - (_offsetXForkHorizontal * iXForkDirection);
            lnForkUpper.Y1 = _destination.Y - (_sizeYForkVertical / 2);
            lnForkUpper.X2 = _destination.X;
            lnForkUpper.Y2 = _destination.Y - (_sizeYForkVertical / 2);

            // Setup the middle horizontal line fork
            lnForkMiddle.X1 = _destination.X - (_offsetXForkHorizontal * iXForkDirection);
            lnForkMiddle.Y1 = _destination.Y;
            lnForkMiddle.X2 = _destination.X;
            lnForkMiddle.Y2 = _destination.Y;

            // Setup the lower line
            lnForkLower.X1 = _destination.X - (_offsetXForkHorizontal * iXForkDirection);
            lnForkLower.Y1 = _destination.Y + (_sizeYForkVertical / 2);
            lnForkLower.X2 = _destination.X;
            lnForkLower.Y2 = _destination.Y + (_sizeYForkVertical / 2);

            // Setup the main line                
            lnMainLine.X2 = _destination.X - (_offsetXForkHorizontal * iXForkDirection);
            lnMainLine.Y2 = _destination.Y;

        }

        /// <summary>
        /// In order to draw the fork connector accurate (showing the fork twisted or not), we need
        /// to inform both parameters (origin and destination) at the same time.
        /// </summary>
        /// <param name="ptOrigin"></param>
        /// <param name="ptDestination"></param>
        /// <param name="doNotShowTwistedBeginConnector"></param>
        /// <param name="showTwistedFork"></param>
        public void SetOriginAndDestination(Point ptOrigin, Point ptDestination, bool doNotShowTwistedBeginConnector, bool showTwistedFork)
        {
            //Origin = ptOrigin;
            SetOrigin(ptOrigin, ptDestination, doNotShowTwistedBeginConnector);
            SetDestination(ptDestination, showTwistedFork);
        }


        #region ISelectable Members

        /// <summary>
        /// Return the flag that indicates whether the object is selected or not
        /// </summary>
        public bool IsSelected
        {
            get { return _isObjectSelected; }
        }

        /// <summary>
        /// Select the object:
        /// 
        ///   - On the UI side, color the connector as red.
        ///   - On the data side, set the isObjectSelected flag to true
        /// </summary>
        public void Select()
        {
            //lnMainLine.Stroke = new SolidColorBrush(Colors.Red);
            colorFullConector(Colors.Red);            
            _isObjectSelected = true;
        }

        public void unSelect()
        {
            colorFullConector(Colors.Black);            
            _isObjectSelected = false;
        }

        #endregion

        private void colorFullConector(Color color)
        {
            lnOriginEndPoint.Stroke = new SolidColorBrush(color); ;
            lnForkUpper.Stroke = new SolidColorBrush(color); ;
            lnForkMiddle.Stroke = new SolidColorBrush(color); ;
            lnForkLower.Stroke = new SolidColorBrush(color); ;
            lnForkVertical.Stroke = new SolidColorBrush(color); ;
            lnMainLine.Stroke = new SolidColorBrush(color);            
        }

        private void lnConnector_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Let's keep it simple... we already have in the root canvas
            // machinery to transform the mouse coordinate to the table related
            // one, let's send a message with this info and let the main view
            // poll for the field clicked            
            if (LButtonDownBubbled != null)
            {
                FireLButtonDownBubbledCustomEvent(e);
                CaptureMouse();
            }            
        }

        /// <summary>
        /// We are giong to fire this event in several places, this method is a helper just to provide a single
        /// entry point and void repeating code everywhere
        /// </summary>
        /// <param name="mousePosition"></param>
        /// <param name="command"></param>
        /// <param name="fieldID">Just used for the CREATE_RELATION command if we are executing another param just
        /// inform it with whatever dummy param, e.g.: -1</param>
        private void FireLButtonDownBubbledCustomEvent(MouseButtonEventArgs e)
        {
            Point mousePosition = new Point(e.GetPosition(null).X, e.GetPosition(null).Y);
            LButtonDownBubbled(this, new RelationCtlMouseOperationBubblingArgs(mousePosition));
        }

    }
}
